#pragma once


public class StaticSingleThreadAllocator 
{
public:
	static inline char* Allocate(int size = 255)
	{
		char* Tmp = CurPtr;
		CurPtr += size;
		return Tmp;
	}
	static inline void Dispose(char* addr)
	{
		CurPtr = min(addr, CurPtr);
	}
private:
	static char* CurPtr;
//	static char* Indexes[100];
//	static int CurID;
	static char allocMem[512*1024];
};

//int StaticSingleThreadAllocator::CurID = 0;
char StaticSingleThreadAllocator::allocMem[512*1024];
//char* StaticSingleThreadAllocator::Indexes[100] = {StaticSingleThreadAllocator::allocMem};
char* StaticSingleThreadAllocator::CurPtr = StaticSingleThreadAllocator::allocMem;


public class SystemMemoryAllocator 
{
public:
	static inline char* Allocate(int size = 255)
	{
		return new char[size];
	}
	static inline void Dispose(char* addr)
	{
		delete [] addr;
	}
};


//==========================================================

template<class TConvAlloc>
class FileInfoManUnmanConverter
{
public:
	static const int DefAlbumSize = 128;
	static const int DefArtistSize = 128;
	static const int DefDateSize = 32;
	static const int DefFileNameSize = 1024;
	static const int DefGenreSize = 32;
	static const int DefTitleSize = 128;

	static AIMP2FileInfo* GetPreparedStructure(int AlbumSize, int ArtistSize, int DateSize, int FileNameSize, int GenreSize, int TitleSize)
	{
		AIMP2FileInfo* finf = (AIMP2FileInfo*)TConvAlloc::Allocate(sizeof(AIMP2FileInfo));
		finf->cbSizeOf = sizeof(AIMP2FileInfo);
		WCHAR* TotalBuffer = (WCHAR*)TConvAlloc::Allocate(2*(AlbumSize+ArtistSize+DateSize+FileNameSize+GenreSize+TitleSize));
		finf->nAlbumLen = AlbumSize-1;
		finf->sAlbum = TotalBuffer; TotalBuffer += AlbumSize; *(TotalBuffer-1) = 0;

		finf->nArtistLen = ArtistSize-1;
		finf->sArtist = TotalBuffer; TotalBuffer += ArtistSize; *(TotalBuffer-1) = 0;

		finf->nDateLen = DateSize - 1;
		finf->sDate = TotalBuffer; TotalBuffer += DateSize; *(TotalBuffer-1) = 0;

		finf->nFileNameLen = FileNameSize - 1;
		finf->sFileName = TotalBuffer; TotalBuffer += FileNameSize; *(TotalBuffer-1) = 0;

		finf->nGenreLen = GenreSize-1;
		finf->sGenre = TotalBuffer; TotalBuffer += GenreSize; *(TotalBuffer-1) = 0;

		finf->nTitleLen = TitleSize-1;
		finf->sTitle = TotalBuffer; TotalBuffer += TitleSize; *(TotalBuffer-1) = 0;

		return finf;
	}

	static AIMP2FileInfo* GetPreparedStructureWithZeroFld(int AlbumSize, int ArtistSize, int DateSize, int FileNameSize, int GenreSize, int TitleSize)
	{
		AIMP2FileInfo* finf = (AIMP2FileInfo*)TConvAlloc::Allocate(sizeof(AIMP2FileInfo));
		ZeroMemory(finf, sizeof(AIMP2FileInfo));
		finf->cbSizeOf = sizeof(AIMP2FileInfo);
		WCHAR* TotalBuffer = (WCHAR*)TConvAlloc::Allocate(2*(AlbumSize+ArtistSize+DateSize+FileNameSize+GenreSize+TitleSize));
		finf->nAlbumLen = AlbumSize-1;
		finf->sAlbum = TotalBuffer; TotalBuffer += AlbumSize; *(TotalBuffer-1) = 0;

		finf->nArtistLen = ArtistSize-1;
		finf->sArtist = TotalBuffer; TotalBuffer += ArtistSize; *(TotalBuffer-1) = 0;

		finf->nDateLen = DateSize - 1;
		finf->sDate = TotalBuffer; TotalBuffer += DateSize; *(TotalBuffer-1) = 0;

		finf->nFileNameLen = FileNameSize - 1;
		finf->sFileName = TotalBuffer; TotalBuffer += FileNameSize; *(TotalBuffer-1) = 0;

		finf->nGenreLen = GenreSize-1;
		finf->sGenre = TotalBuffer; TotalBuffer += GenreSize; *(TotalBuffer-1) = 0;

		finf->nTitleLen = TitleSize-1;
		finf->sTitle = TotalBuffer; TotalBuffer += TitleSize; *(TotalBuffer-1) = 0;

		return finf;
	}

	static AIMP2FileInfo* GetPreparedStructure()
	{
		return GetPreparedStructure(DefAlbumSize, DefArtistSize, DefDateSize, DefFileNameSize, DefGenreSize, DefTitleSize);
	}

	static void DisposeStructure(AIMP2FileInfo*& finf)
	{
		TConvAlloc::Dispose((char*)finf->sAlbum);
		TConvAlloc::Dispose((char*)finf);
		finf = NULL;
	}

	static dotNetInteropPlugin::PluginDev::MAIMPFileInfo^ GetManagedFromUnmanaged(AIMP2FileInfo* finf)
	{
		dotNetInteropPlugin::PluginDev::MAIMPFileInfo^ res = gcnew dotNetInteropPlugin::PluginDev::MAIMPFileInfo();

		res->Album = gcnew System::String(finf->sAlbum);
		res->Artist = gcnew System::String(finf->sArtist);
		res->Date = gcnew System::String(finf->sDate);
		res->FileName = gcnew System::String(finf->sFileName);
		res->Genre = gcnew System::String(finf->sGenre);
		res->Title = gcnew System::String(finf->sTitle);

		res->IsActive = finf->nActive != 0;
		res->BitRate = finf->nBitRate;
		res->ChanelNumber = finf->nChannels;
		res->Duration = System::TimeSpan::FromMilliseconds(finf->nDuration);
		res->FileSize = finf->nFileSize;
		res->Rating = finf->nRating;
		res->SampleRate = finf->nSampleRate;
		res->TrackID = finf->nTrackID;
		return res;
	}

	static void CopyToManagedFromUnmanaged(dotNetInteropPlugin::PluginDev::MAIMPFileInfo^ res, AIMP2FileInfo* finf)
	{
		res->Album = gcnew System::String(finf->sAlbum);
		res->Artist = gcnew System::String(finf->sArtist);
		res->Date = gcnew System::String(finf->sDate);
		res->FileName = gcnew System::String(finf->sFileName);
		res->Genre = gcnew System::String(finf->sGenre);
		res->Title = gcnew System::String(finf->sTitle);

		res->IsActive = finf->nActive != 0;
		res->BitRate = finf->nBitRate;
		res->ChanelNumber = finf->nChannels;
		res->Duration = System::TimeSpan::FromMilliseconds(finf->nDuration);
		res->FileSize = finf->nFileSize;
		res->Rating = finf->nRating;
		res->SampleRate = finf->nSampleRate;
		res->TrackID = finf->nTrackID;
	}

	

	static AIMP2FileInfo* GetUnmanagedFromManaged(dotNetInteropPlugin::PluginDev::IMAIMPFileInfoReadOnly^ finf)
	{
		AIMP2FileInfo* res = GetPreparedStructure(getStrLength(finf->Album)+1, getStrLength(finf->Artist)+1, getStrLength(finf->Date)+1, getStrLength(finf->FileName)+1, getStrLength(finf->Genre)+1, getStrLength(finf->Title)+1);
		CopyManStrToUnman(res->sAlbum, finf->Album);
		CopyManStrToUnman(res->sArtist, finf->Artist);
		CopyManStrToUnman(res->sDate, finf->Date);
		CopyManStrToUnman(res->sFileName, finf->FileName);
		CopyManStrToUnman(res->sGenre, finf->Genre);
		CopyManStrToUnman(res->sTitle, finf->Title);

		res->nActive = finf->IsActive;
		res->nBitRate = finf->BitRate;
		res->nChannels = finf->ChanelNumber;
		res->nDuration = (UInt32)finf->Duration.TotalMilliseconds;
		res->nFileSize = finf->FileSize;
		res->nRating = finf->Rating;
		res->nSampleRate = finf->SampleRate;
		res->nTrackID = finf->TrackID;

		return res;
	}
private:
	static inline void CopyManStrToUnman(WCHAR* Dest, System::String^ Src)
	{
		pin_ptr<const WCHAR> StrPtr = PtrToStringChars(Src);
		CopyMemory(Dest, (void*)StrPtr, (Src->Length+1)*2);
	}

	static inline int getStrLength(System::String^ str)
	{
		if (System::String::IsNullOrEmpty(str))
			return 0;
		return str->Length;
	}
};

